package org.fight.actor;

import java.util.List;

import org.fight.logic.Dispatcher;
import org.fight.net.KcpCodec;
import org.fight.net.KcpConstant;

import com.sojoys.artifact.factory.message.IMessage;
import com.sojoys.artifact.factory.session.ISession;
import com.sojoys.artifact.third.kcp.KCP;
import com.sojoys.artifact.tools.ToolDate;
import com.xiaoleilu.hutool.log.Log;
import com.xiaoleilu.hutool.log.LogFactory;

import akka.actor.AbstractActor;
import akka.japi.pf.ReceiveBuilder;
import io.netty.buffer.ByteBuf;

/**
 * @author : DengYing
 * @CreateDate : 2018年3月2日 下午2:41:27
 * @Description ：Please describe this document
 */
public class SessionActor extends AbstractActor {
	
	static final Log log = LogFactory.get(SessionActor.class);
	
	private ISession session;

	public SessionActor(ISession session) {
		this.session = session;
	}

	@Override
	public Receive createReceive() {
		return ReceiveBuilder.create().match(ActorMsg.class, msg -> {
			switch (msg.getType()) {
			case NETTY:
				receive(msg);
				break;
			case KCP_UPDATE:
				update();
				break;
			case KCP_SEND:
				send(msg);
				break;
			}
			
		}).build();
	}

	
	private void send(ActorMsg msg){
		KCP kcp = session.getAttr(KcpConstant.KCP);
		if (kcp != null) {
			// 取得加密钥匙
			byte[] data = KcpCodec.encoder((IMessage)msg.getObj(), session.getAttr(KcpConstant.ENCRYPTION_KEYS));
			// 是否需要立即更新
			session.setAttr(KcpConstant.NEED_UPDATE, true);
			// 更新最后写数据时间
			session.setAttr(KcpConstant.LAST_WRITE_TIME, System.currentTimeMillis());
			kcp.Send(data);
		}
	}
	
	
	/** 接收消息 */
	private void receive(ActorMsg msg) {
		byte[] data = (byte[]) msg.getObj();
		KCP kcp = session.getAttr(KcpConstant.KCP);
		if (kcp.Input(data) != 0) {
			return;
		}
		// 
		session.setAttr(KcpConstant.NEED_UPDATE, true);
		// 更新最后写数据时间
		session.setAttr(KcpConstant.LAST_READ_TIME, System.currentTimeMillis());
		// 收取一个MTU大小的缓冲区
		data = new byte[255 * (kcp.IKCP_MTU_DEF - kcp.IKCP_OVERHEAD)];
		int n = kcp.Recv(data);
		if (n < 0) {
			return;
		}

		// 取得session的缓存
		ByteBuf buf = session.getAttr(KcpConstant.BYTE_BUF);
		buf.writeBytes(data, 0, n);
		
		// 解码消息
		List<IMessage> messages = KcpCodec.decoder(buf, session.getAttr(KcpConstant.DECRYPTION_KEYS));

		// 进入消息路由
		for (IMessage message : messages) {
			Dispatcher.me().disp(session, message);
		}
	}

	
	public void update(){
		long now = System.currentTimeMillis();
		
		int conv = session.getAttr(KcpConstant.CONV);
		long readTimeOut = now - (long)session.getAttr(KcpConstant.LAST_READ_TIME);
		long writeTimeOut = now - (long)session.getAttr(KcpConstant.LAST_WRITE_TIME);
		
		// 掉线
		if (readTimeOut > ToolDate.TIME_MINUTE || writeTimeOut > ToolDate.TIME_MINUTE) {
			session.close();
			log.error("{} 超时 ",conv);
			return;
		}
		KCP kcp = session.getAttr(KcpConstant.KCP);
		if (kcp.WaitSnd() > 128) {
			session.close();
			log.error("{} 待发送包超过128个 ",conv);
			return;
		}
		long nextUpdateTime = session.getAttr(KcpConstant.NEXT_UPDATE_TIME);
		boolean needUpdate = session.getAttr(KcpConstant.NEED_UPDATE);
		// 如果不需要更新 || 时间未到 = 不更新
//		if (!needUpdate || nextUpdateTime < now)
//			return;
		kcp.Update(now);
		session.setAttr(KcpConstant.NEXT_UPDATE_TIME,kcp.Check(now));
		session.setAttr(KcpConstant.NEED_UPDATE,false);
	}
}
